﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data.Common;
using Transcend.FileUploader.Utility;
using Transcend.Archive.Exchange.Services;
using Transcend.Utility;
using System.IO;
using Transcend.Archive.CSScan.Store.Contract;
using Transcend.Archive.Exchange.Contract;
namespace Transcend.OnlineImageImp
{
    public partial class frmExport : Form
    {
        DbConnection _conn;
        decimal _userId;
        public DictionaryWraper Settings { get; set; }
        public string ExpSubTypeId { get; set; }
        public string ExpNodeId { get; set; }
        public frmExport()
        {
            InitializeComponent();
            gvBiz.AutoGenerateColumns = false;
            ExpSubTypeId = "23510,23501";
            ExpNodeId = "90";
        }
        public frmExport(DbConnection conn, decimal userId)
            : this()
        {
            _conn = conn; _userId = userId;
        }
        /// <summary>
        /// 图像导出路径设置
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void tsbPath_Click(object sender, EventArgs e)
        {
            using (FolderBrowserDialog fbd = new FolderBrowserDialog())
            {
                if (!string.IsNullOrEmpty(txtPath.Text) && System.IO.Directory.Exists(txtPath.Text))
                {
                    fbd.SelectedPath = txtPath.Text;
                }
                else
                {
                    //fbd.RootFolder = Environment.SpecialFolder.MyComputer;
                    fbd.SelectedPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
                }
                fbd.ShowNewFolderButton = true;
                if (fbd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    txtPath.Text = fbd.SelectedPath;
                }
            }
        }

        void BindData()
        {
            string sqlString = "select b.bizid ,b.bizno,u.name UserName,n.stepname,n.createdate ReceiveTime,\n" +
                "b.curuserid from bizarchive b, wfnode n,csuser u where b.curuserid=u.userid and b.wfnodeid=n.wfnodeid\n" +
                "  and b.subtypeid in (" + ExpSubTypeId + ")";  //and b.wfnodeid=90";
            if (!string.IsNullOrEmpty(ExpNodeId))
            {
                sqlString += " And b.wfnodeid=" + ExpNodeId;
            }

            sqlString = string.Format("With qry as ({0})\n", sqlString);

            string where = "";
            if (mnuCurrentUser.Checked)
                where = string.Format("curuserid={0}", _userId);
            if (!string.IsNullOrEmpty(txtBizNo.Text.Trim()))
            {
                if (!string.IsNullOrEmpty(where)) where += " And ";
                where += string.Format(" BizNo='%{0}%'", txtBizNo.Text.Trim().Replace("'", "''"));
            }

            string sql = sqlString + " Select * From qry ";
            if (!string.IsNullOrEmpty(where)) sql += " where " + where;

            sql += " order by bizid desc";
            List<OnlineDataRow> rows = new List<OnlineDataRow>();  //所有数据行
            using (var cmd = _conn.CreateCommand())
            {
                cmd.CommandText = sql;
                using (var reader = cmd.ExecuteReader())
                {
                    while (reader.Read())
                    {
                        var row = new OnlineDataRow();
                        row.BizId = System.Convert.ToDecimal(reader["BizId"]);   //业务序号 
                        row.BizNo = reader.IsDBNull(1) ? "" : reader.GetString(1);  //业务编号
                        row.UserName = reader.GetString(2);  //用户名称
                        row.StepName = reader.GetString(3);  //步骤名称
                        row.ReceiveTime = reader.GetDateTime(4);
                        rows.Add(row);
                    }
                }
            }
            gvBiz.DataSource = rows;
        }

        /// <summary>
        /// 设置是否只选择当前用户的数据
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void mnuCurrentUser_Click(object sender, EventArgs e)
        {
            mnuCurrentUser.Checked = !mnuCurrentUser.Checked;
        }

        /// <summary>
        /// 查询数据
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnQuery_ButtonClick(object sender, EventArgs e)
        {
            BindData();
        }
        /// <summary>
        /// 导出数据或图像
        /// </summary>
        /// <param name="bizId"></param>
        /// <param name="exportType">导出数据类型：1、结构化数据，2、图形数据</param>
        private void ExpBiz(decimal bizId, int exportType)
        {
            decimal boxId;
            string configFile;
            string storePath;
            string password;

            storePath = txtPath.Text;
            if (string.IsNullOrEmpty(storePath))
            {
                MessageBox.Show("请选择存储路径。");
                return;
            }
            password = GetDbConfigValue(330002);  //加密密码
            if (exportType == 1 && string.IsNullOrEmpty(password))
            {
                MessageBox.Show("导出结构化数据需要加密，但密码为空，请登录档案系统，转入到【主城区国土分局档案管理信息系统>>研发中心>>参数配置>>档案业务-档案移交】下,配置参数编号为330002的项目。");
                return;
            }
            configFile = Settings.GetString("uploader.strcutureDataDescriptor");  //配置文件
            if (string.IsNullOrEmpty(configFile))
            {
                MessageBox.Show("档案导出配置文件为空，请重新配置[app.settings\\uploader.strcutureDataDescriptor]。");
                return;
            }
            if (!System.IO.File.Exists(configFile))
            {
                MessageBox.Show(string.Format("档案导出配置文件[{0}]不存在。", configFile));
                return;
            }
            WriteLogger(string.Format("配置文件:{0}\r\n存储路径：{1}\r\n加密密码：{2}", configFile, storePath, password));
            List<decimal> chestes = new List<decimal>();
            using (var cmd = _conn.CreateCommand())
            {
                string sql = "Select chestid from archiveChest where bizid={0}";
                Db.InitCommand(cmd, sql, bizId);
                using (var reader = cmd.ExecuteReader())
                {
                    bool hasChest = false;
                    while (reader.Read())
                    {
                        decimal chestId = Db.GetValue<decimal>(reader, 0);
                        hasChest = true;
                        try
                        {
                            switch (exportType)
                            {
                                case 1:
                                    //导出结构化数据
                                    WriteLogger(string.Format("开始导出业务[业务序号：{0},箱序号: {1}]结构化数据... ", bizId, chestId));
                                    string fileName = ExportStructureData(bizId, chestId, configFile, storePath, password);
                                    WriteLogger(string.Format("导出业务[业务序号：{0},箱序号: {1}]的结构化文件为：{2}", bizId, chestId, fileName));
                                    WriteLogger(string.Format("导出业务[业务序号：{0},箱序号: {1}]结构数据已完成。 ", bizId, chestId));
                                    break;
                                case 2:
                                    WriteLogger(string.Format("开始导出业务[业务序号：{0},箱序号: {1}]图像原文数据... ", bizId, chestId));
                                    string imgPath = ExportImageData(bizId, chestId, storePath, password);
                                    WriteLogger(string.Format("导出业务[业务序号：{0},箱序号: {1}]的图像原文路径为：{2}", bizId, chestId, imgPath));
                                    WriteLogger(string.Format("导出业务[业务序号：{0},箱序号: {1}]图像原文路径已完成。 ", bizId, chestId));
                                    break;
                                //导出图形
                            }
                            chestes.Add(chestId);
                        }
                        catch (Exception e)
                        {
                            WriteLogger(e);
                            MessageBox.Show(e.Message);
                            return;
                        }
                    }
                    if (!hasChest)
                    {
                        switch (exportType)
                        {
                            case 1:
                                //导出结构化数据
                                WriteLogger(string.Format("开始导出业务[业务序号：{0} 的结构化数据... ", bizId));
                                string fileName = ExportStructureData(bizId, null, configFile, storePath, password);
                                WriteLogger(string.Format("导出业务[业务序号：{0} 的结构化文件为：{1}", bizId, fileName));
                                WriteLogger(string.Format("导出业务[业务序号：{0} 结构数据已完成。 ", bizId));
                                break;
                            case 2:
                                WriteLogger(string.Format("开始导出业务[业务序号：{0} 的图像原文数据... ", bizId));
                                string imgPath = ExportImageData(bizId, null, storePath, password);
                                WriteLogger(string.Format("导出业务[业务序号：{0} 的图像原文路径为：{1}", bizId, imgPath));
                                WriteLogger(string.Format("导出业务[业务序号：{0} 图像原文路径已完成。 ", bizId));
                                break;
                            //导出图形
                        }
                    }
                };
            }

        }

        private void WriteLogger(string message)
        {
            Application.DoEvents();
            txtLogger.AppendText("\n");
            txtLogger.AppendText(message);
            txtPath.ScrollToCaret();
            Application.DoEvents();
        }

        private void WriteLogger(Exception ex)
        {
            string msg = string.Format("错误信息:{0}\r\n,错误跟踪：{1}", ex.Message, ex.StackTrace);
            WriteLogger(msg);
        }
        /// <summary>
        /// 获取配置信息
        /// </summary>
        /// <param name="configId"></param>
        /// <returns></returns>
        private string GetDbConfigValue(decimal configId)
        {
            string sql = "Select configValue from baseconfig where id={0}";
            return Db.ExecuteScaler<string>(_conn, sql, configId);
        }


        private string ExportStructureData(decimal bizId, decimal? boxId, string configFile, string storePath, string password)
        {
            var cfg = ConfigReader2.GetConfig(configFile);
            var exp = new DocExchange2(cfg);
            string chestBarcode = string.Empty, bizNo = string.Empty;

            string sql = "Select FileId from BizDocFile b where b.bizid={0} And nvl(b.chestId,0)=nvl({1},0)";

            List<decimal> fileList = new List<decimal>();
            using (var cmd = _conn.CreateCommand())
            {
                Db.InitCommand(cmd, sql, new object[] { bizId, boxId });
                using (var reader = cmd.ExecuteReader())
                {
                    while (reader.Read())
                    {
                        fileList.Add(Db.GetValue<decimal>(reader, 0));
                    }
                }
                //箱条码
                if (boxId != null)
                {
                    sql = "select chestcode from archivechest where chestid={0}";
                    Db.InitCommand(cmd, sql, new object[] { boxId });
                    chestBarcode = Db.NVL<string>(cmd.ExecuteScalar(), string.Empty);
                }
                else
                {
                    chestBarcode = "all";
                }
                //业务编号
                sql = "select bizno from bizarchive where bizid={0}";
                Db.InitCommand(cmd, sql, new object[] { bizId });
                bizNo = Db.NVL<string>(cmd.ExecuteScalar(), string.Empty);

            }
            if (fileList.Count == 0)
            {
                throw new Exception(string.Format("导出结构化数据时出错。业务序号：{0},箱序号: {1} 下没有选择档案。", bizId, boxId));
            }



            var xml = exp.Export(_conn, bizId, fileList, _userId, 0m);  //导出XML
            xml.DocumentElement.SetAttribute("chestCode", chestBarcode);

            var path = System.IO.Path.Combine(storePath, bizId.ToString(), boxId.ToString(), "Structure");
            if (!System.IO.Directory.Exists(path))
                System.IO.Directory.CreateDirectory(path);  //如果目录不存在，就创建
            string fileName = System.IO.Path.Combine(path, string.Format("data-{0}-{1}.csdbf", bizNo, chestBarcode));
            byte[] buffer;
            using (var stream = new System.IO.MemoryStream())
            {
                xml.Save(stream);
                buffer = new byte[stream.Length];
                stream.Position = 0;
                stream.Read(buffer, 0, buffer.Length);
                stream.Close();
            }
            using (Ionic.Zip.ZipFile zf = new Ionic.Zip.ZipFile(System.Text.Encoding.UTF8))
            {
                zf.Password = password;
                zf.Encryption = Ionic.Zip.EncryptionAlgorithm.WinZipAes256;

                zf.AddEntry("content.xml", buffer);
                using (var fileStream = System.IO.File.Create(fileName))
                {
                    zf.Save(fileStream);
                }
            }
            sql = "update ArchiveChest a set a.packDir={0},packTime=sysdate where chestID={1}";
            using (var cmd = _conn.CreateCommand())
            {
                //保存结构化数据导出文件的路径
                Db.InitCommand(cmd, sql, new object[] { fileName, boxId });
                cmd.ExecuteNonQuery();
            }

            return fileName;
        }

        private string ExportImageData(decimal bizId, decimal? boxId, string storePath, string password)
        {

            string sql, PackServiceName;
            decimal applyId;
            string chestBarcode = string.Empty, bizNo = string.Empty;

            sql = "Select apptypeid from csscan.dsscanapptype where lower(appname)='docfile'";
            applyId = Db.ExecuteScaler<decimal>(_conn, sql);

            if (applyId == 0) applyId = 5;
            decimal instId = 0;
            List<FileKey> volFile;

            if (boxId != null)
            {
                sql = "select f.filekey filekeyName,d.fileid,d.DocNo from lsfilekey f,docfile d,bizdocfile b " +
                      "where f.FileKeyID(+)=d.FileKeyID and b.fileid=d.fileid and d.isDestoryed=0 and b.bizid={0} " +
                      " And Exists(select 1 from ArchiveChest c where c.bizid=b.bizid and c.chestID=b.chestID " +
                      " And c.chestID={1}) And b.chestID={1}";
            }
            else
            {
                sql = "select f.filekey filekeyName,d.fileid,d.DocNo from lsfilekey f,docfile d,bizdocfile b " +
                      "where f.FileKeyID(+)=d.FileKeyID and b.fileid=d.fileid and d.isDestoryed=0 and b.bizid={0}";
            }
            int isPackZip = 0;
            string[] packServices = new string[]{
                    "Transcend.Archive.Exchange.Services.EncryptedImage",
                    "Transcend.Archive.Exchange.Services.ZipImagePack"
                };

            using (var cmd = _conn.CreateCommand())
            {
                Db.InitCommand(cmd, sql, new object[] { bizId, boxId });
                using (var reader = cmd.ExecuteReader())
                {
                    volFile = Db.Select<FileKey>(reader).ToList();
                }

                //箱条码
                if (boxId != null)
                {
                    sql = "select chestcode from archivechest where chestid={0}";
                    Db.InitCommand(cmd, sql, new object[] { boxId });
                    chestBarcode = Db.NVL<string>(cmd.ExecuteScalar(), string.Empty);
                }
                else
                {
                    chestBarcode = "all";
                }
                //业务编号
                sql = "select bizno from bizarchive where bizid={0}";
                Db.InitCommand(cmd, sql, new object[] { bizId });
                bizNo = Db.NVL<string>(cmd.ExecuteScalar(), string.Empty);

                sql = "Select configValue from baseConfig where id={0}";
                Db.InitCommand(cmd, sql, new object[] { 330003m });
                isPackZip = Db.NVL<int>(cmd.ExecuteScalar(), 0);
                if (isPackZip >= packServices.Length || isPackZip < 0)
                {
                    throw new Exception("导出文件存储方式（系统参数编号为：330003）,其值只能是0或1。");
                }
                PackServiceName = packServices[isPackZip];
            }

            string root = string.Format("{0}\\{1}\\{2}", bizId, boxId, "image");

            string tempDir = storePath;  //保存的临时文件夹

            string fullPath = string.Empty;
            Dictionary<string, System.IO.Stream> allFiles = new Dictionary<string, System.IO.Stream>();
            string zipFile = string.Empty;
            ImageStore Store = null;
            ImagePack PackService = SpringHelper.Get<ImagePack>(PackServiceName);
            PackService.Password = password;
            try
            {
                #region 导出业务下所有图像文件，并追加到压缩包中
                foreach (var vol in volFile.GroupBy(it => it.FileKeyName))
                {

                    string volPath = root;      //卷路径
                    if (!string.IsNullOrEmpty(vol.Key)) volPath = System.IO.Path.Combine(volPath, vol.Key);
                    foreach (var doc in vol)
                    {
                        if (Store != null)
                        {
                            Store.Dispose();
                        }
                        Store = Transcend.Archive.CSScan.Stores.StoreFactory.GetDsStore(_conn, doc.FileId, applyId, "CSScan");  //获取档案的Store

                        string filePath = Path.Combine(volPath, string.IsNullOrEmpty(doc.DocNo) ? doc.FileId.ToString() : doc.DocNo);   //宗目录名称


                        sql = "select instId from csscan.dsinstance where pkvalue={0} and apptypeid={1} and nvl(status,1)=1";
                        instId = Db.NVL<decimal>(Db.ExecuteScaler(_conn, sql, doc.FileId, applyId), 0);

                        //查询图像名称
                        sql = "select p.imgno, i.credname,p.rawfilename, row_number() over(order by i.itemid) seqno, row_number() over(partition by i.credname order by p.pageno) pgno\n" +
                        "  from csscan.dsitem i,csscan.dspage p\n" +
                        "  where i.itemid=p.itemid and p.status=1 and instid={0}\n" +
                        "  order by seqno,pgno";


                        //System.Text.RegularExpressions.Regex.Match(""
                        using (var cmd = _conn.CreateCommand())
                        {
                            Db.InitCommand(cmd, sql, new object[] { instId });

                            using (var reader = cmd.ExecuteReader())
                            {

                                while (reader.Read())
                                {
                                    var oldFileName = Db.GetValue<string>(reader, "rawfilename");

                                    string fileName = "{0}-{1}-{2}{3}";
                                    string seqno = Db.GetValue<string>(reader, "seqno"); //顺序号
                                    string credName = Db.GetValue<string>(reader, "credname");  //证件名称
                                    string credPageNo = Db.GetValue<string>(reader, "pgno");    //证件页序号
                                    string extName = System.IO.Path.GetExtension(oldFileName);  //文件扩展名
                                    decimal ImageNo = Db.GetValue<decimal>(reader, "imgno");    //图像Id

                                    var buffer = Store.GetImage(instId, ImageNo);

                                    //fileName = string.Format(fileName, seqno.PadLeft(4, '0'), credName, credPageNo.PadLeft(2, '0'), extName);
                                    fileName = oldFileName;
                                    fullPath = string.Format(@"{0}\{1}", tempDir, filePath);
                                    string fullName = string.Format(@"{0}\{1}", fullPath, fileName);
                                    if (!System.IO.Directory.Exists(fullPath))
                                    {
                                        System.IO.Directory.CreateDirectory(fullPath);
                                    }

                                    if (buffer != null && buffer.Length > 0)
                                    {
                                        PackService.Add(fullName, buffer);
                                    }
                                    else
                                    {
                                        System.Diagnostics.EventLog.WriteEntry("DocExport", string.Format("在导出档案[{0}]下的文件[{1}]时，发现其图像文件不存在或为空。", doc.FileId, fileName));
                                    }
                                }
                            }
                        }
                    }
                }
                #endregion


                #region 压缩文件并将文件发送到客户端
                if (isPackZip == 1)
                {
                    zipFile = string.Format(@"{0}\{1}\img-{2}-{3}.csdbf", tempDir, root, bizNo, chestBarcode);
                }
                else
                {
                    zipFile = string.Format(@"{0}\{1}", tempDir, root);
                }
                PackService.Pack(System.IO.Path.Combine(tempDir, root), zipFile);  //将文件进行打包,如果此处文件是加密文件，则不会进行打包
                #endregion

                #region 更新数据库
                sql = "update ArchiveChest a set a.packDirBlob={0},packTime=sysdate where chestID={1}";
                using (var cmd = _conn.CreateCommand())
                {
                    //保存结构化数据导出文件的路径
                    Db.InitCommand(cmd, sql, new object[] { zipFile, boxId });
                    int cnt = cmd.ExecuteNonQuery();
                }
                #endregion
            }
            finally
            {
                if (Store != null)
                {
                    Store.Dispose();
                }
            }
            return zipFile;

        }

        private void tsbExportStructure_Click(object sender, EventArgs e)
        {
            ExportIt(1);   //导出结构化数据
        }

        private void tsbExportImage_Click(object sender, EventArgs e)
        {
            ExportIt(2);    //导出图形数据
        }

        private void ExportIt(int expType)
        {
            if (gvBiz.SelectedRows.Count == 0)
            {
                MessageBox.Show("请选中一个业务后再进行导出。");
                return;
            }
            var rowIndex = gvBiz.SelectedRows[0].Index;
            List<OnlineDataRow> data = gvBiz.DataSource as List<OnlineDataRow>;
            var row = data[rowIndex];
            txtLogger.Clear();
            Cursor = Cursors.WaitCursor;
            tabContainer.SelectedTab = tbLogPage;
            WriteLogger("正在导出，请稍后...");
            ExpBiz(row.BizId, expType);  //导出业务结构化数据
            //tsbExportImage.Selected = true;

            Cursor = Cursors.Default;
        }
    }
}
